#region Copyright (c) 2000-2013 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{                                                                   }
{                                                                   }
{       Copyright (c) 2000-2013 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2013 Developer Express Inc.

using System;
using System.Collections;
using System.Collections.Generic;
#if TESTUTILS
namespace DevExpress.Xpf.DemoBase.TestUtils {
#else 
#if SLDESIGN
namespace DevExpress.Xpf.Core.Design.CoreUtils {
#else
#if DXWINDOW
namespace DevExpress.Internal.DXWindow {
#else
namespace DevExpress.Xpf.Core.Native {
#endif
#endif
#endif
	public class CompositeEnumerator<T> : IEnumerator {
		int currentEnumeratorIndex;
		object current;
		IEnumerator[] enumerators;
		static readonly object NoneObject = new object();
		public CompositeEnumerator(params IEnumerator[] enumerators) {
			if(enumerators == null || enumerators.Length == 0) {
				throw new ArgumentNullException("enumerators");
			}
			this.enumerators = enumerators;
			this.currentEnumeratorIndex = -1;
			this.current = NoneObject;
		}
		bool IEnumerator.MoveNext() {
			if(currentEnumeratorIndex < 0)
				currentEnumeratorIndex = 0;
			if(enumerators[currentEnumeratorIndex].MoveNext()) {
				current = enumerators[currentEnumeratorIndex].Current;
				return true;
			}
			if(currentEnumeratorIndex < enumerators.Length - 1) {
				currentEnumeratorIndex++;
				return ((IEnumerator)this).MoveNext();
			}
			current = NoneObject;
			return false;
		}
		void IEnumerator.Reset() {
			currentEnumeratorIndex = -1;
			current = NoneObject;
			foreach(IEnumerator item in enumerators) {
				item.Reset();
			}
		}
		object IEnumerator.Current {
			get {
				if(current != NoneObject)
					return current;
				throw new InvalidOperationException();
			}
		}
	}
	public abstract class NestedObjectEnumeratorBase : IEnumerator {
		#region inner class
		protected class EnumStack : Stack<IEnumerator> {
			public IEnumerator TopEnumerator {
				get { return (IsEmpty == false) ? Peek() : null; }
			}
			public bool IsEmpty {
				get { return Count == 0; }
			}
			public EnumStack() {
			}
		}
		#endregion
		protected static readonly IEnumerator EmptyEnumerator = (new object[0]).GetEnumerator();
		IEnumerator objects;
		protected EnumStack stack;
		protected IEnumerator Enumerator { get { return (IEnumerator)this; } }
		public object CurrentParent {
			get { return EnumeratorHelper.GetFirst<object>(GetParents()); }
		}
		public IEnumerable<object> GetParents() {
			IEnumerator<IEnumerator> en = stack.GetEnumerator();
			if(en.MoveNext()) {
				while(en.MoveNext()) {
					yield return en.Current.Current;
				}
			}
		}
		public int Level { get { return stack.Count; } }
		protected NestedObjectEnumeratorBase(object obj) {
			this.objects = new object[] { obj }.GetEnumerator();
			stack = new EnumStack();
			Reset();
		}
		object IEnumerator.Current {
			get { return stack.TopEnumerator.Current; }
		}
		public virtual bool MoveNext() {
			if(stack.IsEmpty) {
				stack.Push(objects);
				return stack.TopEnumerator.MoveNext();
			}
			IEnumerator nestedObjects = GetNestedObjects(Enumerator.Current);
			if(nestedObjects.MoveNext()) {
				stack.Push(nestedObjects);
				return true;
			}
			while(stack.TopEnumerator.MoveNext() == false) {
				stack.Pop();
				if(stack.IsEmpty)
					return false;
			}
			return true;
		}
		protected abstract IEnumerator GetNestedObjects(object obj);
		public virtual void Reset() {
			stack.Clear();
			objects.Reset();
		}
	}
	public delegate void EnumerateDelegate<OfType>(OfType item);
	public static class EnumeratorHelper {
		public static int Count<T>(IEnumerable<T> list) {
			int i = 0;
			foreach(T item in list) {
				i++;
			}
			return i;
		}
		public static int Count(IEnumerable list) {
			int i = 0;
			foreach(object item in list) {
				i++;
			}
			return i;
		}
		public static IEnumerable<T> Combine<T>(params IEnumerable<T>[] enumerables) {
			foreach(IEnumerable<T> enumerable in enumerables) {
				foreach(T item in enumerable) {
					yield return item;
				}
			}
		}
		public static T GetFirst<T>(IEnumerable<T> source) {
			foreach(T item in source) {
				return item;
			}
			return default(T);
		}
		public static bool Exists<T>(IEnumerable<T> enumerable, T toFind) {
			return null != Find<T>(enumerable,
				delegate(T item) {
					return Object.ReferenceEquals(item, toFind);
				});
		}
		public static bool Exists(IEnumerable enumerable, object toFind) {
			return null != Find(enumerable,
				delegate(object item) {
					return Object.ReferenceEquals(item, toFind);
				});
		}
		public static IEnumerable<T> Filter<T>(IEnumerable<T> enumerable, Predicate<T> predicate) {
			foreach(T item in enumerable) {
				if(predicate(item)) {
					yield return item;
				}
			}
		}
		public static T Find<T>(IEnumerable<T> enumerable, Predicate<T> predicate) {
			foreach(T item in enumerable) {
				if(predicate(item)) {
					return item;
				}
			}
			return default(T);
		}
		public static object Find(IEnumerable enumerable, Predicate<object> predicate) {
			foreach(object item in enumerable) {
				if(predicate(item)) {
					return item;
				}
			}
			return null;
		}
		public static IEnumerable<TOutput> Convert<TOutput, TInput>(IEnumerable<TInput> source) where TInput : TOutput {
			foreach(TInput item in source) {
				yield return (TOutput)item;
			}
		}
		public static IEnumerable<TOutput> Convert<TInput, TOutput>(IEnumerable<TInput> source, Converter<TInput, TOutput> castDelegate) {
			foreach(TInput item in source) {
				yield return castDelegate(item);
			}
		}
		public static T[] ToArray<T>(IEnumerable<T> source) {
			return new List<T>(source).ToArray();
		}
		public static void SafeEnumerate<OfType>(IEnumerable<OfType> source, EnumerateDelegate<OfType> handler) {
			int index = 0;
			List<OfType> list = new List<OfType>(source);
			while(index < list.Count) {
				handler(list[index]); 
				list = new List<OfType>(source);
				index++;
			}
		}
		public static void ForEach(IEnumerator enumerator, Func<object, bool> handler) {
			while(enumerator.MoveNext())
				if(!handler(enumerator.Current))
					return;
		}
		public static void ForEach<T>(IEnumerator<T> enumerator, Func<object, bool> handler) {
			while(enumerator.MoveNext())
				if(!handler(enumerator.Current))
					return;
		}
	}
	public class EmptyEnumerator : IEnumerator {
		EmptyEnumerator() { }
		public bool MoveNext() { return false; }
		public void Reset() { }
		public object Current { get { throw new InvalidOperationException(); } }
		static IEnumerator instanceCore;
		public static IEnumerator Instance {
			get {
				if(instanceCore == null) instanceCore = new EmptyEnumerator();
				return instanceCore;
			}
		}
	}
	public class MergedEnumerator : IEnumerator {
		readonly IEnumerator[] Enumerators;
		public MergedEnumerator(IEnumerator[] enumerators) {
			Enumerators = enumerators;
		}
		#region IEnumerator Members
		IEnumerator currentEnumerator;
		object IEnumerator.Current {
			get {
				if (currentEnumerator != null) return currentEnumerator.Current;
				throw new NotSupportedException();
			}
		}
		int index = -1;
		bool IEnumerator.MoveNext() {
			while (EnsureCurrentEnumerator()) {
				if (currentEnumerator.MoveNext()) return true;
				currentEnumerator = null;
			}
			return false;
		}
		bool EnsureCurrentEnumerator() {
			if (currentEnumerator == null) {
				if (++index < Enumerators.Length) {
					currentEnumerator = Enumerators[index];
				}
			}
			return currentEnumerator != null;
		}
		void IEnumerator.Reset() {
			currentEnumerator = null;
			index = -1;
		}
		#endregion
	}
}
